package com.senyint.hip.fhir.provider;

import java.util.ArrayList;
import java.util.Date;
import java.util.Deque;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.r4.model.IdType;
import org.hl7.fhir.r4.model.MedicationRequest;
import org.hl7.fhir.r4.model.OperationOutcome;
import org.springframework.stereotype.Component;

import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.annotation.Create;
import ca.uhn.fhir.rest.annotation.Delete;
import ca.uhn.fhir.rest.annotation.History;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.rest.annotation.RequiredParam;
import ca.uhn.fhir.rest.annotation.ResourceParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.annotation.Update;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;

/**
 * *******description*******
 * 药品医嘱
 * *************************
 *
 * @author lcg
 * @date 2019/07/01 14:24
 */
@Component
public class MedicationRequestProvider implements IResourceProvider {
	
	
	/**
	 * 临时存储数据
	 */
    private Map<Long, Deque<MedicationRequest>> medicationRequests = new HashMap<Long, Deque<MedicationRequest>>();

    private long myNextId = 1;
	

	@Override
	public Class<MedicationRequest> getResourceType() {
		 
		return MedicationRequest.class;
	}
	
	
	
	 @Create()
	 public MethodOutcome createMedicationRequest(@ResourceParam MedicationRequest mr) {

	        long id = myNextId++;

	        String versionId = addNewVersionMr(mr, id);

	        MethodOutcome retVal = new MethodOutcome();
	        retVal.setId(new IdType("MedicationRequest", String.valueOf(id), versionId));

	        // You can also add an OperationOutcome resource to return
	        // This part is optional though:
	        OperationOutcome outcome = new OperationOutcome();
	        outcome.setIdElement(new IdType("MedicationRequest", String.valueOf(id), versionId));
	        outcome.addIssue().setDiagnostics("新增药品医嘱成功").setId(String.valueOf(id));
	        retVal.setOperationOutcome(outcome);

	        return retVal;
	    }

	 
	    @Delete()
	    public MethodOutcome removeMedicationRequest(@IdParam IdType theId) {
	        Long id;
	        try {
	            id = theId.getIdPartAsLong();
	        } catch (DataFormatException e) {
	            throw new InvalidRequestException("Invalid ID " + theId.getValue() + " - Must be numeric");
	        }

	        if (!medicationRequests.containsKey(id)) {
	            throw new ResourceNotFoundException(theId);
	        }

	        medicationRequests.remove(id);

	        MethodOutcome retVal = new MethodOutcome();
	        OperationOutcome outcome = new OperationOutcome();
	        outcome.addIssue().setDiagnostics("删除成功").setId(String.valueOf(id));
	        retVal.setOperationOutcome(outcome);

	        return retVal;
	    }
	 
	    
	    @Update()
	    public MethodOutcome updateMedicationRequest(@IdParam IdType theId, @ResourceParam MedicationRequest mr) {

	        Long id;
	        try {
	            id = theId.getIdPartAsLong();
	        } catch (DataFormatException e) {
	            throw new InvalidRequestException("Invalid ID " + theId.getValue() + " - Must be numeric");
	        }

	        /*
	         * Throw an exception (HTTP 404) if the ID is not known
	         */
	        if (!medicationRequests.containsKey(id)) {
	            throw new ResourceNotFoundException(theId);
	        }

	        String versionId = addNewVersionMr(mr, id);

	        MethodOutcome retVal = new MethodOutcome();
	        retVal.setId(new IdType("MedicationRequest", String.valueOf(id), versionId));

	        // You can also add an OperationOutcome resource to return
	        // This part is optional though:
	        OperationOutcome outcome = new OperationOutcome();
	        outcome.setIdElement(new IdType("MedicationRequest", String.valueOf(id), versionId));
	        outcome.addIssue().setDiagnostics("更新药品医嘱成功").setId(String.valueOf(id));
	        retVal.setOperationOutcome(outcome);

	        return retVal;
	    }
	    
	    
	    
	    
	    @History()
	    public List<MedicationRequest> readEncounterBundle(@IdParam IdType theId) {
	        Deque<MedicationRequest> retVal;
	        try {
	            retVal = medicationRequests.get(theId.getIdPartAsLong());
	        } catch (NumberFormatException e) {
	            /*
	             * If we can't parse the ID as a long, it's not valid so this is an unknown resource
	             */
	            throw new ResourceNotFoundException(theId);
	        }

	        List<MedicationRequest> mrList = new ArrayList<>();
	        for (MedicationRequest mr : retVal) {
	        	mrList.add(mr);
	        }

	        return mrList;
	    }

	    
	     
	
    @Search
    public List<MedicationRequest> findDrUsingArbitraryCtriteria() {
        LinkedList<MedicationRequest> retVal = new LinkedList<MedicationRequest>();

        for (Deque<MedicationRequest> nextMrList : medicationRequests.values()) {
        	MedicationRequest nextMr = nextMrList.getLast();
            retVal.add(nextMr);
        }

        return retVal;
    }
    
    
    
    @Read(version = true)
    public MedicationRequest readMedicationRequest(@IdParam IdType theId) {
        Deque<MedicationRequest> retVal;
        try {
            retVal = medicationRequests.get(theId.getIdPartAsLong());
        } catch (NumberFormatException e) {
            /*
             * If we can't parse the ID as a long, it's not valid so this is an unknown resource
             */
            throw new ResourceNotFoundException(theId);
        }

        if (theId.hasVersionIdPart() == false) {
            return retVal.getLast();
        } else {
            for (MedicationRequest nextVersion : retVal) {
                String nextVersionId = nextVersion.getIdElement().getVersionIdPart();
                if (theId.getVersionIdPart().equals(nextVersionId)) {
                    return nextVersion;
                }
            }
            // No matching version
            throw new ResourceNotFoundException("Unknown version: " + theId.getValue());
        }

    }
    
    
    
    
    @Search()
    public List<MedicationRequest> findByMedicationNameAndId(@RequiredParam(name = "medication") String medicationName,@RequiredParam(name ="id") String id) {

        LinkedList<MedicationRequest> retVal = new LinkedList<MedicationRequest>();

        NAMELOOP:
        for (Deque<MedicationRequest> nextMrlist : medicationRequests.values()) {
        	MedicationRequest nextMr = nextMrlist.getLast();
             Long idPartAsLong = nextMr.getIdElement().getIdPartAsLong();
             
             if(StringUtils.isNotEmpty(medicationName)&&StringUtils.isNotEmpty(id)) {
            	 if (medicationName.equals(nextMr.getMedicationReference().getDisplay())&& id.equals(idPartAsLong.toString())) {
                     retVal.add(nextMr);
                     break NAMELOOP;
                 }
             }else if (StringUtils.isNotEmpty(medicationName)&&StringUtils.isEmpty(id)) {
            	 
            	 if (medicationName.equals(nextMr.getMedicationReference().getDisplay())) {
                     retVal.add(nextMr);
                     break NAMELOOP;
                 }
            	 
             }else if (StringUtils.isEmpty(medicationName)&&StringUtils.isNotEmpty(id)) {
            	 if (id.equals(idPartAsLong.toString())) {
                     retVal.add(nextMr);
                     break NAMELOOP;
                 }
             }
           

        }

        return retVal;
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    private String addNewVersionMr(MedicationRequest mr, long id) {

        Date publishedDate;

        if (!medicationRequests.containsKey(id)) {
        	medicationRequests.put(id, new LinkedList<MedicationRequest>());
            publishedDate = InstantDt.withCurrentTime().getValue();
        } else {
        	MedicationRequest oldMr = medicationRequests.get(id).getLast();
            publishedDate = oldMr.getMeta().getLastUpdated();

        }


        mr.getMeta().setLastUpdated(InstantDt.withCurrentTime().getValue());
        Deque<MedicationRequest> existingVersions = medicationRequests.get(id);

        String newVersion = Integer.toString(existingVersions.size());

        //版本号
        mr.getMeta().setVersionId(newVersion);

        // Create an ID with the new version and assign it back to the resource
        IdDt newId = new IdDt("MedicationRequest", Long.toString(id), newVersion);
        mr.setId(newId);

        existingVersions.add(mr);
        return newVersion;
    }
	
	
	
	
	
	
	

}
